home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / h / vd2 / system / atomic.h next >
Encoding:
C/C++ Source or Header  |  2007-04-08  |  9.3 KB  |  270 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #ifndef f_VD2_SYSTEM_ATOMIC_H
  27. #define f_VD2_SYSTEM_ATOMIC_H
  28.  
  29. #include <vd2/system/vdtypes.h>
  30.  
  31. // Intrinsics available in VC6.0
  32. extern "C" long __cdecl _InterlockedDecrement(volatile long *p);
  33. extern "C" long __cdecl _InterlockedIncrement(volatile long *p);
  34. extern "C" long __cdecl _InterlockedCompareExchange(volatile long *p, long n, long p_compare);
  35. extern "C" long __cdecl _InterlockedExchange(volatile long *p, long n);
  36. extern "C" long __cdecl _InterlockedExchangeAdd(volatile long *p, long n);
  37.  
  38. #pragma intrinsic(_InterlockedDecrement)
  39. #pragma intrinsic(_InterlockedIncrement)
  40. #pragma intrinsic(_InterlockedCompareExchange)
  41. #pragma intrinsic(_InterlockedExchange)
  42. #pragma intrinsic(_InterlockedExchangeAdd)
  43.  
  44. // Intrinsics available in VC7.1. Note that the compiler is smart enough to
  45. // use straight LOCK AND/OR/XOR if the return value is not needed; otherwise
  46. // it uses a LOCK CMPXCHG loop.
  47. #if _MSC_VER >= 1310
  48.     extern "C" long __cdecl _InterlockedAnd(volatile long *p, long n);
  49.     extern "C" long __cdecl _InterlockedOr(volatile long *p, long n);
  50.     extern "C" long __cdecl _InterlockedXor(volatile long *p, long n);
  51.  
  52.     #pragma intrinsic(_InterlockedAnd)
  53.     #pragma intrinsic(_InterlockedOr)
  54.     #pragma intrinsic(_InterlockedXor)
  55. #endif
  56.  
  57. // Intrinsics available with AMD64
  58. #ifdef _M_AMD64
  59.     extern "C" void *__cdecl _InterlockedExchangePointer(void *volatile *pp, void *p);
  60.     #pragma intrinsic(_InterlockedExchangePointer)
  61.     extern "C" void *__cdecl _InterlockedCompareExchangePointer(void *volatile *pp, void *p, void *compare);
  62.     #pragma intrinsic(_InterlockedCompareExchangePointer)
  63. #endif
  64.  
  65. inline void *VDAtomicCompareExchangePointer(void *volatile *pp, void *p, void *compare) {
  66. #ifdef _M_AMD64
  67.     return _InterlockedCompareExchangePointer(pp, p, compare);
  68. #else
  69.     return (void *)(sintptr)_InterlockedCompareExchange((volatile long *)(volatile sintptr *)pp, (long)(sintptr)p, (long)(sintptr)compare);
  70. #endif
  71. }
  72.  
  73. ///////////////////////////////////////////////////////////////////////////
  74. /// \class VDAtomicInt
  75. /// \brief Wrapped integer supporting thread-safe atomic operations.
  76. ///
  77. /// VDAtomicInt allows integer values shared between threads to be
  78. /// modified with several common operations in a lock-less manner and
  79. /// without the need for explicit barriers. This is particularly useful
  80. /// for thread-safe reference counting.
  81. ///
  82. class VDAtomicInt {
  83. protected:
  84.     volatile int n;
  85.  
  86. public:
  87.     VDAtomicInt() {}
  88.     VDAtomicInt(int v) : n(v) {}
  89.  
  90.     bool operator!() const { return !n; }
  91.     bool operator!=(volatile int v) const  { return n!=v; }
  92.     bool operator==(volatile int v) const { return n==v; }
  93.     bool operator<=(volatile int v) const { return n<=v; }
  94.     bool operator>=(volatile int v) const { return n>=v; }
  95.     bool operator<(volatile int v) const { return n<v; }
  96.     bool operator>(volatile int v) const { return n>v; }
  97.  
  98.     ///////////////////////////////
  99.  
  100.     /// Atomically exchanges a value with an integer in memory.
  101.     static inline int staticExchange(volatile int *dst, int v) {
  102.         return (int)_InterlockedExchange((volatile long *)dst, v);
  103.     }
  104.  
  105.     /// Atomically adds one to an integer in memory.
  106.     static inline void staticIncrement(volatile int *dst) {
  107.         _InterlockedExchangeAdd((volatile long *)dst, 1);
  108.     }
  109.  
  110.     /// Atomically subtracts one from an integer in memory.
  111.     static inline void staticDecrement(volatile int *dst) {
  112.         _InterlockedExchangeAdd((volatile long *)dst, -1);
  113.     }
  114.  
  115.     /// Atomically subtracts one from an integer in memory and returns
  116.     /// true if the result is zero.
  117.     static inline bool staticDecrementTestZero(volatile int *dst) {
  118.         return 1 == _InterlockedExchangeAdd((volatile long *)dst, -1);
  119.     }
  120.  
  121.     /// Atomically adds a value to an integer in memory and returns the
  122.     /// result.
  123.     static inline int staticAdd(volatile int *dst, int v) {
  124.         return (int)_InterlockedExchangeAdd((volatile long *)dst, v) + v;
  125.     }
  126.  
  127.     /// Atomically adds a value to an integer in memory and returns the
  128.     /// old result (post-add).
  129.     static inline int staticExchangeAdd(volatile int *dst, int v) {
  130.         return _InterlockedExchangeAdd((volatile long *)dst, v);
  131.     }
  132.  
  133.     /// Atomically compares an integer in memory to a compare value and
  134.     /// swaps the memory location with a second value if the compare
  135.     /// succeeds. The return value is the memory value prior to the swap.
  136.     static inline int staticCompareExchange(volatile int *dst, int v, int compare) {
  137.         return _InterlockedCompareExchange((volatile long *)dst, v, compare);
  138.     }
  139.  
  140.     ///////////////////////////////
  141.  
  142.     int operator=(int v) { return n = v; }
  143.  
  144.     int operator++()        { return staticAdd(&n, 1); }
  145.     int operator--()        { return staticAdd(&n, -1); }
  146.     int operator++(int)        { return staticExchangeAdd(&n, 1); }
  147.     int operator--(int)        { return staticExchangeAdd(&n, -1); }
  148.     int operator+=(int v)    { return staticAdd(&n, v); }
  149.     int operator-=(int v)    { return staticAdd(&n, -v); }
  150.  
  151. #if _MSC_VER >= 1310
  152.     void operator&=(int v)    { _InterlockedAnd((volatile long *)&n, v); }    ///< Atomic bitwise AND.
  153.     void operator|=(int v)    { _InterlockedOr((volatile long *)&n, v); }        ///< Atomic bitwise OR.
  154.     void operator^=(int v)    { _InterlockedXor((volatile long *)&n, v); }    ///< Atomic bitwise XOR.
  155. #else
  156.     /// Atomic bitwise AND.
  157.     void operator&=(int v) {
  158.         __asm mov eax,v
  159.         __asm mov ecx,this
  160.         __asm lock and dword ptr [ecx],eax
  161.     }
  162.  
  163.     /// Atomic bitwise OR.
  164.     void operator|=(int v) {
  165.         __asm mov eax,v
  166.         __asm mov ecx,this
  167.         __asm lock or dword ptr [ecx],eax
  168.     }
  169.  
  170.     /// Atomic bitwise XOR.
  171.     void operator^=(int v) {
  172.         __asm mov eax,v
  173.         __asm mov ecx,this
  174.         __asm lock xor dword ptr [ecx],eax
  175.     }
  176. #endif
  177.  
  178.     operator int() const {
  179.         return n;
  180.     }
  181.  
  182.     /// Atomic exchange.
  183.     int xchg(int v) {
  184.         return staticExchange(&n, v);
  185.     }
  186.  
  187.     // 486 only, but much nicer.  They return the actual result.
  188.  
  189.     int inc()            { return operator++(); }                ///< Atomic increment.
  190.     int dec()            { return operator--(); }                ///< Atomic decrement.
  191.     int add(int v)        { return operator+=(v); }                ///< Atomic add.
  192.  
  193.     // These return the result before the operation, which is more inline with
  194.     // what XADD allows us to do.
  195.  
  196.     int postinc()        { return operator++(0); }                ///< Atomic post-increment.
  197.     int postdec()        { return operator--(0); }                ///< Atomic post-decrement.
  198.     int postadd(int v)    { return staticExchangeAdd(&n, v); }    ///< Atomic post-add.
  199.  
  200. };
  201.  
  202. ///////////////////////////////////////////////////////////////////////////
  203.  
  204. class VDAtomicFloat {
  205. protected:
  206.     volatile float n;
  207.  
  208. public:
  209.     VDAtomicFloat() {}
  210.     VDAtomicFloat(float v) : n(v) {}
  211.  
  212.     bool operator!=(float v) const  { return n!=v; }
  213.     bool operator==(float v) const { return n==v; }
  214.     bool operator<=(float v) const { return n<=v; }
  215.     bool operator>=(float v) const { return n>=v; }
  216.     bool operator<(float v) const { return n<v; }
  217.     bool operator>(float v) const { return n>v; }
  218.  
  219.     float operator=(float v) { return n = v; }
  220.  
  221.     operator float() const {
  222.         return n;
  223.     }
  224.  
  225.     /// Atomic exchange.
  226.     float xchg(float v) {
  227.         union { int i; float f; } converter = {VDAtomicInt::staticExchange((volatile int *)&n, *(const int *)&v)};
  228.  
  229.         return converter.f;
  230.     }
  231. };
  232.  
  233. ///////////////////////////////////////////////////////////////////////////
  234. /// \class VDAtomicPtr
  235. /// \brief Wrapped pointer supporting thread-safe atomic operations.
  236. ///
  237. /// VDAtomicPtr allows a shared pointer to be safely manipulated by
  238. /// multiple threads without locks. Note that atomicity is only guaranteed
  239. /// for the pointer itself, so any operations on the object must be dealt
  240. /// with in other manners, such as an inner lock or other atomic
  241. /// operations. An atomic pointer can serve as a single entry queue.
  242. ///
  243. template<typename T>
  244. class VDAtomicPtr {
  245. protected:
  246.     T *volatile ptr;
  247.  
  248. public:
  249.     VDAtomicPtr() {}
  250.     VDAtomicPtr(T *p) : ptr(p) { }
  251.  
  252.     operator T*() const { return ptr; }
  253.     T* operator->() const { return ptr; }
  254.  
  255.     T* operator=(T* p) {
  256.         return ptr = p;
  257.     }
  258.  
  259.     /// Atomic pointer exchange.
  260.     T *xchg(T* p) {
  261. #ifdef _M_AMD64
  262.         return ptr == p ? p : (T *)_InterlockedExchangePointer((void *volatile *)&ptr, p);
  263. #else
  264.         return ptr == p ? p : (T *)_InterlockedExchange((volatile long *)&ptr, (long)p);
  265. #endif
  266.     }
  267. };
  268.  
  269. #endif
  270.